import { Injectable } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';
import config from '../../config';
import BusinessError from 'libs/common/utils/BusinessError';
import LoginDto from '../dto/LoginDto';
import RegisterDto from '../dto/RegisterDto';
import { InjectRedis } from '@nestjs-modules/ioredis';
import { Redis } from 'ioredis';
import MailService from './email.service';
import RoleKey from '../common/enum/RoleKey';
import AuthTokenDto from '../dto/AuthTokenDto';
import UserApi from '../api/user.api';

@Injectable()
export default class AuthService {
  static loginKey = 'login_';
  static registerKey = 'register_';
  constructor(
    @InjectRedis() private readonly redis: Redis,
    private readonly mailService: MailService,
    private readonly userApi: UserApi,
  ) {}

  sign(payload: object | string | Buffer) {
    return jwt.sign(payload, config.secretOrPrivateKey);
  }

  decode(token: string) {
    return jwt.decode(token);
  }

  async login({ email, code }: LoginDto): Promise<AuthTokenDto> {
    const user = await this.userApi.getUserByEmail(email);
    if (!user) {
      throw new BusinessError('该人员未注册！', 400);
    }
    const status = this.validateLoginCode({
      email,
      code,
    });
    if (!status) {
      throw new BusinessError('验证码无效！', 400);
    }
    const userInfo = {
      id: user.id,
      email: email,
      name: user.name,
      roleKeys: await this.userApi.getRoleKeysByUserId(user.id),
    };
    return this.createAuthToken(userInfo);
  }

  async applyToJoin(registerDto: RegisterDto) {
    const userId = await this.register(registerDto);
    const user = await this.userApi.getUserByEmail(registerDto.email);
    const userInfo = {
      id: userId,
      email: registerDto.email,
      name: user.name,
      roleKeys: await this.userApi.getRoleKeysByUserId(user.id),
    };
    return this.createAuthToken(userInfo);
  }

  async register(registerDto: RegisterDto) {
    const user = await this.userApi.getUserByEmail(registerDto.email);
    if (user) {
      throw new BusinessError('该人员已注册！', 400);
    }
    const status = await this.validateRegisterCode(registerDto);

    if (!status) {
      throw new BusinessError('验证码无效！', 400);
    }
    const userInfo = {
      email: registerDto.email,
      name: '用户',
      roleKeys: [RoleKey.COMMON_USER],
    };
    const userId = await this.userApi.createUser(userInfo);
    return userId; //注册成功返回用户id
  }

  async validateLoginCode({ code, email }: LoginDto): Promise<boolean> {
    const _code = await this.redis.get(AuthService.loginKey + email);
    return _code === code;
  }

  async validateRegisterCode({ code, email }: RegisterDto): Promise<boolean> {
    const _code = await this.redis.get(AuthService.registerKey + email);
    return _code === code;
  }

  static createCode(len: number) {
    let code = '';
    while (len--) {
      const str = Math.floor(Math.random() * 10);
      code += str;
    }
    return code;
  }

  async getLoginCode(email: string) {
    const key = AuthService.loginKey + email;
    await this.redis.get(key).then((data) => {
      if (data) {
        throw new BusinessError('验证码已发送，请注意查收！', 400);
      }
    });
    const user = await this.userApi.getUserByEmail(email);
    if (!user) {
      throw new BusinessError('该人员未注册！', 400);
    }
    const code = AuthService.createCode(6);
    await this.redis.set(key, code).then(async (data) => {
      await this.redis.expire(key, 60 * 5);
      return data; //成功会返回ok
    });
    await this.mailService.sendVerificationCode(email, code); //发送验证码
  }

  async getRegisterCode(email: string) {
    const key = AuthService.registerKey + email;
    await this.redis.get(key).then((data) => {
      if (data) {
        throw new BusinessError('验证码已发送，请注意查收！', 400);
      }
    });
    const user = await this.userApi.getUserByEmail(email);
    if (user) {
      throw new BusinessError('该人员已注册！', 400);
    }
    const code = AuthService.createCode(6);
    await this.redis.set(key, code).then(async (data) => {
      await this.redis.expire(key, 60 * 5);
      return data; //成功会返回ok
    });
    await this.mailService.sendVerificationCode(email, code); //发送验证码
  }

  createToken(payload: object): string {
    return this.sign(payload);
  }
  validateToken(token: string): object {
    return this.decode(token) as object;
  }
  createRefToken(token: string): string {
    return this.sign(token);
  }
  validateRefToken(refToken: string): string {
    return this.decode(refToken) as string;
  }
  createAuthToken(user: object): {
    token: string;
    refToken: string;
  } {
    const _token = this.createToken(user);
    return {
      token: _token,
      refToken: this.createRefToken(_token),
    };
  }
  refreshToken(token: string, refToken: string): AuthTokenDto {
    const playload = this.validateRefToken(refToken);
    if (playload === token) {
      const user = this.validateToken(token);
      return this.createAuthToken(user);
    }
  }
}
